﻿using System;
using System.Collections;
using System.Data.SqlTypes;
using System.Security.Principal;
using ActiveDirectoryUtilities.DirectoryServiceAccess;
using Microsoft.SqlServer.Server;
using System.Diagnostics;
using System.DirectoryServices.Protocols;
using AccessActiveDirectory;
using ActiveDirectoryUtilities.CommonLibrary.Unsafe;

public partial class UserDefinedFunctions
{
	[SqlFunction(FillRowMethodName = "Fill_fn_GetTrusts", DataAccess = DataAccessKind.Read
		, TableDefinition =
		"SourceDomainFqdn NVARCHAR(MAX)"
		+ ", SourceDomainNetBIOS NVARCHAR(MAX)"
		+ ", TargetDomainFqdn NVARCHAR(MAX)"
		+ ", TargetDomainNetBIOSName NVARCHAR(MAX)"
		+ ", TrustFlags NVARCHAR(MAX)"
		+ ", TrustAttributes NVARCHAR(MAX)"
		+ ", SelectiveAuthenticationEnabled BIT"
		+ ", SidFilteringEnabled BIT"
		+ ", PasswordLastSet DATETIME"
		+ ", OutboundVerified BIT"
		+ ", InboundVerified BIT"
		)]
	public static IEnumerable fn_GetTrusts(SqlString fqdnDomainName, SqlInt32 trustFlags)
	{
		EventLogTraceListener eltl = new EventLogTraceListener("Application");
		if (ConfiguredSettings.TraceLevel >= 4)
		{
			Trace.Listeners.Add(eltl);
		}

		WindowsImpersonationContext executionContext = null;
		try
		{
			WindowsIdentity callerId = SqlContext.WindowsIdentity;
			if (callerId != null)
			{
				executionContext = callerId.Impersonate();
				string domainName = string.Empty;
				if (!fqdnDomainName.IsNull)
				{
					domainName = (string)fqdnDomainName;
				}

				NetApi32.DS_DOMAIN internalTrustFlags;
				if (!trustFlags.IsNull)
				{
					internalTrustFlags = (NetApi32.DS_DOMAIN)((int)trustFlags);
				}
				else
				{
					internalTrustFlags = NetApi32.DS_DOMAIN.ALL;
				}

				Domain d = null;
				try
				{
					if (!string.IsNullOrEmpty(domainName))
					{
						d = Domain.GetDomain((string)fqdnDomainName);
					}
					else
					{
						d = Domain.GetCurrentDomain();
					}

					return d.GetAllTrustRelationships(internalTrustFlags);
				}
				catch (LdapException ex)
				{
					if (ex.ErrorCode == 81)
					{
						throw new ApplicationException("Could not contact domain:  " + (!string.IsNullOrEmpty(domainName) ? domainName : "Current domain"));
					}
					else
					{
						SharedLogic.LogTraceInfo(eltl, ex, TraceLevel.Error);
						throw ex;
					}
				}
				catch (Exception ex)
				{
					SharedLogic.LogTraceInfo(eltl, ex, TraceLevel.Error);
					throw ex;
				}

				throw new ApplicationException("Invalid codepath traversed.  Caller should never make it here.");
			}
		}
		finally
		{
			if (Trace.Listeners.Contains(eltl))
			{
				Trace.Listeners.Remove(eltl);
			}
			if (executionContext != null)
			{
				executionContext.Undo();
			}
		}
		return null;
	}

	private static void Fill_fn_GetTrusts(
		object o
		, out SqlString sourceDomainFqdn
		, out SqlString sourceDomainNetBIOS
		, out SqlString targetDomainFqdn
		, out SqlString targetDomainNetBiosName
		, out SqlString trustFlags
		, out SqlString trustAttributes
		, out SqlBoolean selectiveAuthenticationEnabled
		, out SqlBoolean sidFilteringEnabled
		, out SqlDateTime passwordLastSet
		, out SqlBoolean outboundVerified
		, out SqlBoolean inboundVerified
		)
	{
		DomainTrust dt = (DomainTrust)o;
		sourceDomainFqdn = dt.SourceDomain.DnsDomainName;
		sourceDomainNetBIOS = dt.SourceDomain.NetBiosName;
		targetDomainNetBiosName = dt.TargetNetbiosDomainName;
		targetDomainFqdn = dt.TargetDnsDomainName;
		trustFlags = dt.Flags.ToString();
		trustAttributes = dt.TrustAttributes.ToString();
		selectiveAuthenticationEnabled = dt.SelectiveAuthEnabled;
		sidFilteringEnabled = dt.SidFilteringEnabled;

		//password
		if (DateTime.Compare(dt.PasswordLastSet, (DateTime)SqlDateTime.MinValue) < 0)
		{
			passwordLastSet = SqlDateTime.Null;
		}
		else
		{
			passwordLastSet = dt.PasswordLastSet;
		}

		outboundVerified = SqlBoolean.Null;
		inboundVerified = SqlBoolean.Null;

	}
};

